package net.com.sunkey.api;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;

import net.com.sunkey.protobuf.CertificateResponse.CertificateResponseData;
import net.com.sunkey.protobuf.ChangeRoomSucceedResponse.ChangeRoomSucceedResponseData;
import net.com.sunkey.protobuf.CreateRoomSucceedResponse.CreateRoomSucceedResponseData;
import net.com.sunkey.protobuf.GetZoneInfoResponse.GetZoneInfoResponseData;
import net.com.sunkey.protobuf.JoinRoomSucceedResponse.JoinRoomSucceedResponseData;
import net.com.sunkey.protobuf.JoinServerSucceedResponse.JoinServerSucceedResponseData;
import net.com.sunkey.protobuf.NewMessageResponse.NewMessageResponseData;
import net.com.sunkey.protobuf.NewRoomResponse.NewRoomResponseData;
import net.com.sunkey.protobuf.NewUserResponse.NewUserResponseData;
import net.com.sunkey.protobuf.Protocol.MessageHandler;
import net.com.sunkey.protobuf.RoomData.Room;
import net.com.sunkey.protobuf.RoomListResponse.RoomListResponseData;
import net.com.sunkey.protobuf.RoomRemoveResponse.RoomRemoveResponseData;
import net.com.sunkey.protobuf.UserData.User;
import net.com.sunkey.protobuf.UserLeaveResponse.UserLeaveResponseData;
import net.com.sunkey.protobuf.UserListResponse.UserListResponseData;


public class DispatcherHandler{
    private DataInputStream inputStream;
	private DataOutputStream outputStream;
	private Connection connection;


	public DispatcherHandler(Connection connection, DataInputStream inputStream, DataOutputStream outputStream) {
    	this.inputStream=inputStream;
    	this.outputStream=outputStream;
    	this.connection=connection;
    }

	public void handlerEvent(String name,Object...objects) {
		Object target=Connection.getObject(name);
		if (target==null)
			return;
		Class<?> clazz = target.getClass();
		try {
			Method[] ms = clazz.getDeclaredMethods();
			for(Method m : ms){ 
				if(m.getName().equals(name)){
					m.invoke(target, objects);
					return;
				}
			}
		} catch (IllegalAccessException | IllegalArgumentException
					| InvocationTargetException e) {
				e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		
	}
   
    public void messageReceived (int MethodID) throws IOException{
		switch(MethodID){
		case MessageHandler.ServerTimeResponse_VALUE:			
			System.out.println("ServerTimeResponse");
			NetSpeedRequest();
			break;
		case MessageHandler.CertificateResponse_VALUE:
			CertificateResponse();
			break;
		case MessageHandler.JoinServerSucceedResponse_VALUE:
			JoinServerSucceedResponse();
			break;			
		case MessageHandler.JoinRoomSucceedResponse_VALUE:
	    	JoinRoomSucceedResponse();
	    	break;
		case MessageHandler.UserListResponse_VALUE:
	    	UserListResponse();
	    	break;
		case MessageHandler.GetZoneInfoResponse_VALUE:
			GetZoneInfoResponse();
			break;
		case MessageHandler.RoomListResponse_VALUE:
	    	RoomListResponse();
	    	break;
		case MessageHandler.NewUserResponse_VALUE:
	    	NewUserResponse();
	    	break;
		case MessageHandler.UserLeaveResponse_VALUE:
	    	UserLeaveResponse();
	    	break;				
		case MessageHandler.ChangeRoomSucceedResponse_VALUE:
			ChangeRoomResponse();
			break;	
		case MessageHandler.NewMessageResponse_VALUE:
	    	NewMessageResponse();
	    	break;	
		case MessageHandler.NewRoomResponse_VALUE:			
			NewRoomResponse();
			break;	
		case MessageHandler.CreateRoomSucceedResponse_VALUE:
			CreateRoomResponse();
			break;
		case MessageHandler.RoomRemoveResponse_VALUE:
			RoomRemoveResponse();
			break;			
		case MessageHandler.ServerErrorResponse_VALUE:	
			ServerErrorResponse();
			break;
		default:
			parseData();
		}
    }

	private void ServerErrorResponse() throws IOException {
		System.out.println("ServerErrorResponse");
		inputStream.readShort();
		int error=inputStream.readInt();
		System.out.println(MessageHandler.valueOf(error).name());
	}
	private void RoomRemoveResponse() throws IOException {
		System.out.println("RoomRemoveResponse");
		RoomRemoveResponseData inPutMessage=RoomRemoveResponseData.parseFrom(parseData());
		handlerEvent(EventHandler.onRoomRemove,inPutMessage.getRoomid());
	}	
	private void CreateRoomResponse() throws IOException {
		System.out.println("CreateRoomResponse");
		CreateRoomSucceedResponseData inPutMessage=CreateRoomSucceedResponseData.parseFrom(parseData());
		handlerEvent(EventHandler.onCreateRoom,inPutMessage.getRoom());
	}
	private void NewRoomResponse() throws IOException {
		System.out.println("NewRoomRespones");
		NewRoomResponseData inPutMessage=NewRoomResponseData.parseFrom(parseData());
		handlerEvent(EventHandler.onNewRoom,inPutMessage.getRoom());
	}

	private void NewMessageResponse() throws IOException {
    	System.out.println("NewMessageResponse");
    	NewMessageResponseData inPutMessage=NewMessageResponseData.parseFrom(parseData());
    	handlerEvent(EventHandler.onNewMessage,inPutMessage.getRouter(),inPutMessage.getMessage(),inPutMessage.getUsername(),inPutMessage.getUserid());
	}
	
	private void ChangeRoomResponse() throws IOException {
		System.out.println("ChangeRoomResponse");
		ChangeRoomSucceedResponseData inPutMessage=ChangeRoomSucceedResponseData.parseFrom(parseData());
		Room room=inPutMessage.getRoom();
		connection.activeRoomId=room.getId();
		handlerEvent(EventHandler.onChangeRoom,room);
	}
	
	private void UserLeaveResponse() throws IOException {
    	System.out.println("UserLeaveResponse");
    	UserLeaveResponseData inPutMessage=UserLeaveResponseData.parseFrom(parseData());
		handlerEvent(EventHandler.onUserLeave,inPutMessage.getUserid());
	}

	private void NewUserResponse() throws IOException {
    	System.out.println("NewUserResponse");
		NewUserResponseData inPutMessage=NewUserResponseData.parseFrom(parseData());
		handlerEvent(EventHandler.onNewUser,inPutMessage.getUser());
	}


	private void RoomListResponse() throws IOException {
    	System.out.println("RoomListResponse");
		RoomListResponseData inPutMessage=RoomListResponseData.parseFrom(parseData());
	   	for (Iterator<Room> it = inPutMessage.getRoomList().iterator();it.hasNext();){
	   		Room r=it.next();
	   		Connection.roomList.put(r.getId(), r);
	   	}		
		handlerEvent(EventHandler.onRoomList,inPutMessage.getRoomList());
	}

	private void GetZoneInfoResponse() throws IOException{
		System.out.println("GetZoneInfoRespones");
		GetZoneInfoResponseData inPutMessage=GetZoneInfoResponseData.parseFrom(parseData());
		connection.zone=inPutMessage.getZone();
		handlerEvent(EventHandler.onZoneInfo,connection.zone);
	}
	private void UserListResponse() throws IOException {
    	System.out.println("UserListResponse");
    	Connection.userList.clear();
		UserListResponseData inPutMessage=UserListResponseData.parseFrom(parseData());
	   	for (Iterator<User> it = inPutMessage.getUserList().iterator();it.hasNext();){
	   		User r=it.next();
	   		Connection.userList.put(r.getId(), r);
	   	}		
		handlerEvent(EventHandler.onUserList,inPutMessage.getUserList());
	}

	private void JoinRoomSucceedResponse() throws IOException {
    	System.out.println("JoinRoomSucceedResponse");
		JoinRoomSucceedResponseData inPutMessage=JoinRoomSucceedResponseData.parseFrom(parseData());
		Room room= inPutMessage.getRoom();
		connection.activeRoomId=room.getId();
		handlerEvent(EventHandler.onJoinRoom,room);
	}

    private void JoinServerSucceedResponse() throws IOException {
		System.out.println("JoinServerSucceedResponse");    	
		JoinServerSucceedResponseData inPutMessage=JoinServerSucceedResponseData.parseFrom(parseData());
		connection.me=inPutMessage.getUser();
		int pingIntervall = inPutMessage.getPingInterval();
		if(pingIntervall > 0){
			//connection.runPing(pingIntervall);
        }
		handlerEvent(EventHandler.onJoinServer,connection.me);
	}

    
	private void CertificateResponse() throws IOException {
		System.out.println("CertificateResponse");		
		CertificateResponseData data=CertificateResponseData.parseFrom(parseData());
		connection.setCertificate(data.getCertificate());
		handlerEvent(EventHandler.onConnected,data.getDelay());
	}    
	private void NetSpeedRequest() throws IOException {
		System.out.println("NetSpeedRequest");		
    	inputStream.readChar();
		long time=inputStream.readLong();
		ByteArrayOutputStream baos= new ByteArrayOutputStream();
		DataOutputStream dos=new DataOutputStream(baos);
		dos.writeShort(MessageHandler.NetSpeedRequest_VALUE);
		dos.writeChar(8);
		dos.writeLong(time);
		outputStream.write(baos.toByteArray());
		outputStream.flush();

	}
	
	private byte[] parseData() throws IOException {
		int length=inputStream.readChar();
		byte[] bytes = new byte[length];
		inputStream.read(bytes);
		return bytes;
	}
	
}
